package com.bah.tract.security;

import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

import com.bah.tract.client.ErrorHandler;
import com.google.inject.Inject;

public class X509PasswordEncryptor implements PasswordEncryptor {

	private PrivateKey mPrivateKey;
	private PublicKey mPublicKey;

	public static final String CERTIFICATE_PROP = "certificate";

	@Inject
	X509PasswordEncryptor(final Preferences preferences) {
		final String alias = preferences.get(CERTIFICATE_PROP, null);
		updateProperties(alias);

		preferences.addPreferenceChangeListener(new PreferenceChangeListener() {

			@Override
			public final void preferenceChange(final PreferenceChangeEvent evt) {
				if (CERTIFICATE_PROP.equals(evt.getKey())) {
					updateProperties(evt.getNewValue());
				}
			}
		});

	}

	private void updateProperties(final String alias) {
		try {
			mPrivateKey = (PrivateKey) WindowsKeystore.getKeystore().getKey(
					alias, null);
			mPublicKey = WindowsKeystore.getKeystore().getCertificate(alias)
					.getPublicKey();
		} catch (final GeneralSecurityException e) {
			ErrorHandler.handleError(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.bah.tract.security.PasswordEncryptor#encrypt(java.lang.String)
	 */
	@Override
	public String encrypt(final String password)
			throws GeneralSecurityException {
		final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
		cipher.init(Cipher.ENCRYPT_MODE, mPublicKey);
		final byte[] encryptedPass = cipher.doFinal(password.getBytes());
		return Base64.encodeBase64String(encryptedPass);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.bah.tract.security.PasswordEncryptor#decrypt(java.lang.String)
	 */
	@Override
	public String decrypt(final String password)
			throws GeneralSecurityException {
		final byte[] binaryPass = Base64.decodeBase64(password);
		final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
		cipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
		final byte[] encryptedPass = cipher.doFinal(binaryPass);
		return new String(encryptedPass);
	}
}
